import bluetooth,ubluetooth
import struct
import time
from micropython import const
import machine
import myconfig


#ble常量设置，不用动
_IRQ_CENTRAL_CONNECT = const(1)
_IRQ_CENTRAL_DISCONNECT = const(2)
_IRQ_GATTS_WRITE = const(3)

_FLAG_READ = const(0x0002)
_FLAG_WRITE_NO_RESPONSE = const(0x0004)
_FLAG_WRITE = const(0x0008)
_FLAG_NOTIFY = const(0x0010)

_ADV_TYPE_FLAGS = const(0x01)
_ADV_TYPE_NAME = const(0x09)
_ADV_TYPE_UUID16_COMPLETE = const(0x3)
_ADV_TYPE_UUID32_COMPLETE = const(0x5)
_ADV_TYPE_UUID128_COMPLETE = const(0x7)
_ADV_TYPE_UUID16_MORE = const(0x2)
_ADV_TYPE_UUID32_MORE = const(0x4)
_ADV_TYPE_UUID128_MORE = const(0x6)
_ADV_TYPE_APPEARANCE = const(0x19)

#服务注册部分
_UART_UUID = bluetooth.UUID("00001101-0000-1000-8000-00805F9B34FB")

_UART_TX = (
    bluetooth.UUID("00001102-0000-1000-8000-00805F9B34FB"),
    _FLAG_READ | _FLAG_NOTIFY,
)

_UART_RX = (
    bluetooth.UUID("00001103-0000-1000-8000-00805F9B34FB"),
    _FLAG_WRITE | _FLAG_WRITE_NO_RESPONSE,
)

_UART_SERVICE = (
    _UART_UUID,
    (_UART_TX, _UART_RX),
)


#广播负载数据
def advertising_payload(limited_disc=False, br_edr=False, name=None, services=None, appearance=0):
    payload = bytearray()

    def _append(adv_type, value):
        nonlocal payload
        payload += struct.pack("BB", len(value) + 1, adv_type) + value

    _append(
        _ADV_TYPE_FLAGS,
        struct.pack("B", (0x01 if limited_disc else 0x02) + (0x18 if br_edr else 0x04)),
    )

    if name:
        _append(_ADV_TYPE_NAME, name)

    if services:
        for uuid in services:
            b = bytes(uuid)
            if len(b) == 2:
                _append(_ADV_TYPE_UUID16_COMPLETE, b)
            elif len(b) == 4:
                _append(_ADV_TYPE_UUID32_COMPLETE, b)
            elif len(b) == 16:
                _append(_ADV_TYPE_UUID128_COMPLETE, b)

    if appearance:
        _append(_ADV_TYPE_APPEARANCE, struct.pack("<h", appearance))

    return payload


#BLE类
class BLESimplePeripheral:
    def __init__(self,name="Alarm_light"):  #BLE名称
        self._ble = bluetooth.BLE()
        self._ble.active(True)
        self._ble.irq(self._irq)
        ((self._handle_tx, self._handle_rx),) = self._ble.gatts_register_services((_UART_SERVICE,))
        self._connections = set()
        self._write_callback = None
        self._payload = advertising_payload(name=name)
        self._advertise()

    # BLE中断
    def _irq(self, event, data):

        # 新设备连接中断
        if event == _IRQ_CENTRAL_CONNECT:
            conn_handle, _, _ = data
            print("New connection", conn_handle)
            self._connections.add(conn_handle)
            self._advertise()

        # 断开连接中断
        elif event == _IRQ_CENTRAL_DISCONNECT:
            conn_handle, _, _ = data
            print("Disconnected", conn_handle)
            self._connections.remove(conn_handle)
            self._advertise()
        
        # 接收数据中断
        elif event == _IRQ_GATTS_WRITE:
            conn_handle, value_handle = data
            value = self._ble.gatts_read(value_handle)
            if value_handle == self._handle_rx and self._write_callback:
                self._write_callback(value)
                # self.on_rx(self, value)

    # 发送数据
    def send(self, data):
        for conn_handle in self._connections:
            self._ble.gatts_write(21, data)
    
    # 发送提示信息
    def notify(self, data):
        for conn_handle in self._connections:
            try:
                self._ble.gatts_notify(conn_handle,21,data)
            except Exception:
                pass

    def is_connected(self):
        return len(self._connections) > 0

    # 广播蓝牙
    def _advertise(self, interval_us=500000):
        print("Starting advertising")
        self._ble.gap_advertise(interval_us, adv_data=self._payload)

    #接收事件
    def set_rx_callback(self, callback):
        self._write_callback = callback
    

#开启蓝牙功能
def start_ble():
    global global_ble
    global_ble = BLESimplePeripheral(myconfig.devic_id)
    global_ble.set_rx_callback(on_rx)


#蓝牙接收解析数据函数
def on_rx(data):

    try:
        #解码字符
        str = data.decode()    
        # print("on_rx:"+str)

        #获取wifi信息
        if str.split(':')[0]=="get":  
            if str.split(':')[1]=="wifi_name":  
                global_ble.notify('wifi_name:'+myconfig.wifi_name) 

        if str.split(':')[0]=="get": 
            if str.split(':')[1]=="wifi_pass":   
                global_ble.notify('wifi_pass:'+ myconfig.wifi_psw) 
    
        #设置wifi名字
        if str.split(':')[0]=="n":  
            myconfig.wifi_name = str.split(':')[1]

        #设置wifi密码   
        if str.split(':')[0]=="s":    
            myconfig.wifi_psw = str.split(':')[1]

        #读取软件版本
        if str.split(':')[0]=="get": 
            if str.split(':')[1]=="ver":   
                global_ble.notify('ver:'+ myconfig.version) 

        #保存   
        if str.split(':')[0]=="save":
            if str.split(':')[1]=="wifi":
                myconfig.save_config()
                machine.reset()

    except Exception as e:
        print(e)


